#include "upload_link_manager.h"
#include "escal_gui.h"
#include "escal.h"
#include <QTcpSocket>
using namespace Escal;

UploadLinkManager::UploadLinkManager(int socketDescriptor, QObject *parent)
		: BaseLinkManager(parent), socketDescriptor(socketDescriptor),
		socket(NULL), fileManager(NULL), buf_size(0){

	netHandlers[EET_REQUEST_DOWNLOAD_URL] = 
			&UploadLinkManager::onRequestDownloadUrl;
	netHandlers[EET_REQUEST_FILE_INFO] =
			&UploadLinkManager::onRequestFileInfo;
	netHandlers[EET_REQUEST_DOWNLOAD_SECTION] =
			&UploadLinkManager::onRequestDownloadSection;
};

UploadLinkManager::~UploadLinkManager() {
	QThread::quit();
	wait();
	if (socket) socket->deleteLater();
};

void UploadLinkManager::stop() {
	socket->disconnectFromHost();
};

void UploadLinkManager::run() {
	qDebug() << "UploadLinkManager::run()";
	socket = new QTcpSocket();
	socket->setSocketDescriptor(socketDescriptor);
	requestId = 0;
	connect(socket, SIGNAL(readyRead()),
			this, SLOT(onReadSocket()), Qt::DirectConnection);
	connect(socket, SIGNAL(disconnected()),
			this, SLOT(onDisconnect()), Qt::DirectConnection);


	if (socket->bytesAvailable() >= (int)sizeof(BaseEvent)) {
		onReadSocket();
	}
	exec();
};

void UploadLinkManager::onRequestDownloadUrl(void *buffer) {
	qDebug() << "UploadLinkManager::onRequestDownloadUrl";
	RequestDownloadUrl* msg = (RequestDownloadUrl*) buffer;
	BaseTask * task = escalGui->findTaskByUrl(QByteArray(msg->url));
	if (task == NULL) {
		emit writeLog(textCursor, QTime::currentTime()
			.toString(), tr("file not found: %1")
			.arg(msg->url));

		qDebug() << "not task with the url" << msg->url;
		RespondDownloadUrl resp;
		resp.state = -1;
		socket->write((char*)&resp, resp.size);
		socket->disconnectFromHost();
		this->deleteLater();
	} else {
		emit writeLog(textCursor, QTime::currentTime()
			.toString(), tr("file found, reading file: %1")
			.arg(msg->url));
			
		fileManager = task->getFileManager();
		connect(fileManager, SIGNAL(dataRead(quint64, int, qint64,
				const QByteArray&)),
			this, SLOT(onReadFile(quint64, int, qint64, const QByteArray&)));
		task->adopt(this);
		RespondDownloadUrl resp;
		resp.state = 0;
		socket->write((char*)&resp, resp.size);
	};
};

void UploadLinkManager::onRequestFileInfo(void *buffer) {
	qDebug() << "UploadLinkManager::onRequestFileInfo";
	RespondFileInfo resp;
	if (fileManager == NULL) {
		resp.file_size = -1;
	}
	else
	{
		resp.file_size = fileManager->getFileSize();
	}

	socket->write((char*)&resp, resp.size);
};

void UploadLinkManager::onRequestDownloadSection(void *buffer) {
	qDebug() << "UploadLinkManager::onRequestDownloadSection";
	RequestDownloadSection* msg = (RequestDownloadSection*) buffer;
	qDebug() << "offset:" << msg->offset << "length:" << msg->length;
	int pieceIndex = msg->offset / PieceSize;
	int pieceOffset = msg->offset % PieceSize;
	if ( pieceIndex >= fileManager->getPieceNum() )
	{
		qDebug() << "request out of file";
		socket->disconnectFromHost();
		return;
	}
	if (fileManager->isPieceDone(pieceIndex))
	{
		requestId = fileManager->read(pieceIndex, pieceOffset, msg->length);
		emit writeLog(textCursor, QTime::currentTime()
			.toString(), tr("reading offset: %1, length: %2")
			.arg(msg->offset).arg(msg->length));
		
	}
	else
	{
		qDebug() << "piece is not done yet";
	}
};


void UploadLinkManager::onReadSocket() {
	qDebug() << "UploadLinkManager::onReadSocket()";
	int ret;
	BaseEvent * event;
	NetHandlerMap::const_iterator itr;
	if (buf_size < sizeof(BaseEvent)) {
		ret = socket->read(buffer + buf_size, sizeof(BaseEvent) - buf_size);
		if (ret < 0) {
			goto readError;
		}
		buf_size += ret;
		if (buf_size < sizeof(BaseEvent)) {
			return;
		}
	}

	event = (BaseEvent *) buffer;
	if (event->size < sizeof(BaseEvent) || event->size > MAX_EVENT_LENGTH) {
		qDebug() << "get a event of wrong size:" << event->size;
		buf_size = 0;
		return;
	}
	if (buf_size < event->size) {
		ret = socket->read(buffer + buf_size, event->size - buf_size);
		if (ret < 0) {
			goto readError;
		}
		buf_size += ret;
		if (buf_size < event->size) {
			return;
		}
	}

	itr = netHandlers.find(event->type);
	if (itr == netHandlers.end()) {
		qDebug() << "get a event of unknown type:" << event->type;
	}
	else {
		(this->*(itr.value()))(buffer); // call the handler
	}
	buf_size = 0;
	return;
		
readError:
	socket->disconnect();
	buf_size = 0;
	return;
};

void UploadLinkManager::onReadFile(quint64 requestId, int pieceIndex,
		qint64 offset, const QByteArray& data) {
	qDebug() << "UploadLinkManager::onReadFile";
	if (requestId != this->requestId) {
		return;
	}
	RespondDownloadSection resp;
	if (data.size() > sizeof(resp.data)) {
		qDebug() << "data too long!!!";
		return;
	}
	qDebug() << "data.size()" << data.size();
	memcpy(resp.data, data.constData(), data.size());
	resp.offset = pieceIndex * PieceSize + offset;
	resp.length = data.size();
	resp.makeSize();
	if (socket->write((char*)&resp, resp.size) != resp.size)
	{
		qDebug() << "socket->write((char*)&resp, resp.size) != resp.size";
	}
};

void UploadLinkManager::onDisconnect()
{
	qDebug() << "UploadLinkManager::onDisconnect";
	emit linkQuited(this, error);
}

